Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary
Imports System.Runtime.Serialization

Friend Class TH_BikiRom_Down
    Inherits Threads.MultiVersionThread

    Private Enum typCrcVerify
        mismatch
        match
        failed
    End Enum
    ' Friend Event getArray(ByVal sener As Object, ByVal e As TH_BikiRom_DownArgs)

    Friend Sub New(ByRef UsbHandler As Comm.UsbCommunicationHandle, ByRef car As CarBase, ByVal Action As BikiAction)
        MyBase.New("Downloading")
        m_UsbCommHandler = UsbHandler
        m_Action = Action
        m_carBase = car
    End Sub

    ''' <summary>
    ''' Downloads from a sector on the board
    ''' </summary>
    ''' <param name="Sector"></param>
    ''' <param name="Bank"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function DownloadSector(ByVal Sector As Byte, ByVal Bank As Byte, Optional ByVal Offset As UInt16 = 0) As Byte()
        Dim data(SectorSize - 1) As Byte
        Dim packetSize As UInt16 = m_UsbCommHandler.MaxRxPacket - 10 - 6
        Dim packetData(packetSize - 1) As Byte
        Dim rcvData() As Byte = Nothing
        Dim frame As Comm.Comm_Frame = Nothing
        Dim packetAdr As ULong = 0
        Dim response As Comm.Comm_Frame.BikiFrameResponse
        Dim retries As UInt16 = 5

        Try
            m_UsbCommHandler.Timeout = 1000

            For i As Integer = 0 To Offset
                data(i) = &HFF
            Next

            For i As Integer = Offset To (data.Length - 1) Step packetSize
                ' Do Boundary check
                If i + packetSize > data.Length - 1 Then
                    packetSize = data.Length - i
                    ReDim packetData(packetSize - 1)
                    Debug.Print("Packet goes over boundry, decreasing size")
                End If

                ' Real address of packet
                packetAdr = (SectorSize * Sector) + (Bank * BankSize) + i

                Debug.Print("Downloading Address : {0} Len: {1}", Hex(packetAdr), packetSize)

                ' Formulate packet
                frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_FLASH_DATA _
                                            , packetAdr _
                                            , Comm.Comm_Frame.BikiFrameAction.READ, packetData, Comm.Comm_Frame.BikiFrameType.ID_FLASH_DATA)
                response = m_UsbCommHandler.SendFrame(frame, rcvData, , 10)
                If response = Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                    ' Copy out the data
                    Array.Copy(rcvData, 5, data, i, packetSize)

                    retries = 5

                    ' Report the progress back to the main thread
                    IncrementProgress(packetSize)
                Else
                    Return Nothing
                End If

                ' Perform cancel check
                If bgw.CancellationPending Then
                    eventArgs.Cancel = True
                    Return Nothing
                End If
            Next

        Catch ex As Comm_Exceptions
            OnMessage(ex.Description)
            Return Nothing
        End Try

        Return data
    End Function

    ''' <summary>
    ''' Downloads the EEprom contents
    ''' </summary>
    ''' <param name="data"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function DownloadEEprom(ByRef data() As Byte) As Boolean
        Dim packetSize As UInt16 = m_UsbCommHandler.MaxRxPacket - 10 - 6
        Dim packetData(packetSize - 1) As Byte
        Dim rcvData() As Byte = Nothing
        Dim frame As Comm.Comm_Frame = Nothing


        Try
            m_UsbCommHandler.Timeout = 1000

            For i As Integer = 0 To (data.Length - 1) Step packetSize
                ' Do Boundary check
                If i + packetSize > data.Length - 1 Then
                    packetSize = data.Length - i
                    ReDim packetData(packetSize - 1)
                    Debug.Print("Packet goes over boundry, decreasing size")
                End If

                ' Real address of packet

                Debug.Print("Downloading Address : {0} Len: {1}", Hex(i), packetSize)

                ' Formulate packet
                frame = New Comm.Comm_Frame(Comm.Comm_Frame.BikiFrameType.ID_EEPROM_DATA _
                                            , i _
                                            , Comm.Comm_Frame.BikiFrameAction.READ, packetData, Comm.Comm_Frame.BikiFrameType.ID_EEPROM_DATA)
                If m_UsbCommHandler.SendFrame(frame, rcvData, , 10) = Comm.Comm_Frame.BikiFrameResponse.CMD_OK Then
                    ' Copy out the data
                    Array.Copy(rcvData, 5, data, i, packetSize)

                    ' Report the progress back to the main thread
                    IncrementProgress(packetSize)

                    ' Perform cancel check
                    If bgw.CancellationPending Then
                        eventArgs.Cancel = True
                        Throw New USB_exceptions("Thread Canceled")
                        Return False
                    End If
                Else
                    Throw New USB_exceptions("Recieved data does not match request, Firmware or Bikisoft error")
                    Return False
                End If
            Next

        Catch ex As Comm_Exceptions
            OnMessage(ex.Description)
            Return False
        End Try

        Return True
    End Function

    Public Overrides Function HwV2Process() As thread_result
        Dim uint_crc As UInteger
        Dim down_data As Byte() = Nothing
        Dim bObject As Boolean = False
        Dim bStatus As Boolean = True
        Dim bReset As Boolean = False

        ' if CFG, then download that section and open!
        If m_Action And BikiAction.BK_CFG Or m_Action = BikiAction.BK_EVERYTHING Then
            Dim data() As Byte = Nothing

            ' 4000 due to everything will be downlaoded!
            mProgressMax = &H40000 + CarBase.EEPROM_SIZE

            data = Me.DownloadSector(3, 0)
            If Not IsNothing(data) AndAlso data.Length = &H10000 Then
                Me.m_carBase = openCarBase(data)

                If Not IsNothing(m_carBase) Then
                    m_Action = m_Action Or BikiAction.BK_MAP1 Or BikiAction.BK_MAP2 Or BikiAction.BK_MAP3 Or BikiAction.BK_EEPROM

                    mProgressMax -= m_carBase.DataStart * 3

                    'mProgressMax += CarBase.EEPROM_SIZE

                    bObject = True
                Else
                    Return thread_result.rslt_bikisoft_error
                End If
            Else
                Return thread_result.rslt_bikisoft_error
            End If
        Else
            If m_Action And BikiAction.BK_EEPROM Then
                mProgressMax = CarBase.EEPROM_SIZE
            End If

            ' Determine what needs downloading
            Dim data()() As Byte = m_carBase.Maps
            For i As UInt32 = 0 To 2
                If m_Action And (2 ^ i) Then
                    If data Is Nothing Or (Not data Is Nothing AndAlso data(i) Is Nothing) Then
                        m_Action = m_Action Or (2 ^ i)
                    Else
                        CalculateCrc(data(i), MyBase.HwV2Sectors(i))

                        Select Case i
                            Case 0
                                Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC, uint_crc)
                            Case 1
                                Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_2, uint_crc)
                            Case 2
                                Me.m_UsbCommHandler.GetUsbVariable(Biki_USBvars.UV_EcuFLASH_CRC_MAP_3, uint_crc)
                        End Select

                        Debug.Print(String.Format("Down S:{0} {1} vs {2}", i, HwV2Sectors(i)(0).nCrc, uint_crc))

                        If MyBase.HwV2Sectors(i)(0).nCrc <> uint_crc Then
                            m_Action = m_Action Or CUInt(2UL ^ i)
                            mProgressMax += m_carBase.DataEnd - m_carBase.DataStart + 1
                        Else
                            m_Action = m_Action And (&HFFFFFFFFUL Xor CUInt(2UL ^ i))
                        End If

                    End If
                End If
            Next

        End If

        ' if Maps, then download that map.

        ' Download the EEPROM Contents
        If m_Action And BikiAction.BK_EEPROM Then
            Dim eeprom_data(CarBase.EEPROM_SIZE - 1) As Byte
            If Not Me.DownloadEEprom(eeprom_data) Then
                Return thread_result.rslt_comms_error
            Else
                m_carBase.getBikSettings.Data = eeprom_data
            End If
        Else

        End If

        ' Download the Map Contents
        For i As UInt32 = 0 To 2
            If m_Action And (2UL ^ i) Then
                ' download something
                down_data = DownloadSector(i, 0, m_carBase.DataStart)
                bReset = True
                If Not IsNothing(down_data) Then
                    m_carBase.setMap(down_data, i)
                Else
                    Return thread_result.rslt_comms_error
                End If
            End If
        Next

        If bObject Then
            ' Send the object back
            OnObject(m_carBase)
        End If

        If bReset Then
            Return thread_result.rslt_allok_reset_required
        Else
            Return thread_result.rslt_allok
        End If

    End Function

    Public Overrides Function HwV3Process() As thread_result
        Dim data As Byte() = Nothing
        Dim bObject As Boolean = False
        Dim down_data As Byte() = Nothing
        Dim Sectors As typFlashSector()() = HwV3Sectors

        ' if CFG, then download that section and open!
        If m_Action And BikiAction.BK_CFG Or m_Action = BikiAction.BK_EVERYTHING Then
            Dim carData(1)() As Byte
            ' set the initial amount
            mProgressMax = &H20000

            ' Get the data
            carData(0) = Me.DownloadSector(15, 0)
            carData(1) = Me.DownloadSector(15, 1)

            If carData(0) Is Nothing Or carData(1) Is Nothing Or _
            (Not carData(0) Is Nothing AndAlso carData(0).Length <> SectorSize) Or _
            (Not carData(1) Is Nothing AndAlso carData(1).Length <> SectorSize) Then
                OnMessage("Unable to download configuration data")
                Return thread_result.rslt_comms_error
            Else
                Dim carDataWhole(SectorSize * 2 - 1) As Byte
                bObject = True

                ' Combine the arrays
                Array.Copy(carData(0), carDataWhole, SectorSize)
                Array.Copy(carData(1), 0, carDataWhole, SectorSize, SectorSize)

                If BlankPacket(carDataWhole) Then
                    OnMessage("Board is Empty, no configuration data uploaded")
                    Return thread_result.rslt_comms_error
                End If

                ' De-Serialise the data
                Me.m_carBase = openCarBase(carDataWhole)

                m_Action = m_Action Or BikiAction.BK_EEPROM

                If m_carBase Is Nothing Then
                    OnMessage("Unable to open configuration data")
                    Return thread_result.rslt_bikisoft_error
                End If

            End If
        End If

        If Not IsNothing(m_carBase) Then
            Dim mapData()() As Byte

            mapData = Me.m_carBase.Maps

            For i As Integer = 0 To CarBase.MAX_MAPS

                Select Case (CheckCRC(mapData(i), Sectors(i)))
                    Case typCrcVerify.failed
                        OnMessage("Error downloading CRCs")
                        Return False
                    Case typCrcVerify.match
                        Sectors(i)(0).eAction = _eAction.NONE
                    Case typCrcVerify.mismatch
                        Sectors(i)(0).eAction = _eAction.TODO1
                        mProgressMax += SectorSize
                End Select

            Next

            ' Download the EEPROM Contents
            If m_Action And BikiAction.BK_EEPROM Then
                mProgressMax += CarBase.EEPROM_SIZE
                Dim eeprom_data(CarBase.EEPROM_SIZE - 1) As Byte
                If Not Me.DownloadEEprom(eeprom_data) Then
                    OnMessage("Failed to download Bikirom Memory")
                    Return thread_result.rslt_comms_error
                Else
                    m_carBase.getBikSettings.Data = eeprom_data
                End If
            End If

            ' Download the Flash Contents
            For i As Integer = 0 To CarBase.MAX_MAPS
                If Sectors(i)(0).eAction = _eAction.TODO1 Then
                    ' download something
                    down_data = DownloadSector(i, 0, m_carBase.DataStart)

                    If Not IsNothing(down_data) Then
                        m_carBase.setMap(down_data, i)
                    Else
                        OnMessage("Failed to download Board ECU Memory")
                        Return thread_result.rslt_comms_error
                    End If
                End If
            Next

            If bObject Then
                ' Send the object back
                OnObject(m_carBase)
            End If

            Return thread_result.rslt_allok
        Else
            OnMessage("BikiSoft Error, Downloading faulty, contact support")
            Return thread_result.rslt_bikisoft_error
        End If

    End Function

    Public Overrides Function HwV4Process() As thread_result
        Return thread_result.rslt_bikisoft_error
    End Function

    Private Function openCarBase(ByRef Array() As Byte) As CarBase
        Dim f_ncar As CarBase
        Dim f_sel As frmCarSelection
        Dim Deserializer As New BinaryFormatter
        Try
            ' --------------------------- Try Opening New Encrypted AND comp BikiRom File ----------------------------------
            Dim f_encryptStream As New MemoryStream(Array)
            Dim f_decyptStream As New MemoryStream

            ' ---------------------------- Decrypt Stream and Deflate info a memory stream 
            CryptFile(libStrings.getS(0), f_encryptStream, f_decyptStream, False)
            Dim f_uncomp As New MemoryStream
            Dim f_Comp As New MemoryStream(f_decyptStream.ToArray)
            f_encryptStream.Dispose()
            f_decyptStream.Dispose()
            If CompressFile(f_Comp, f_uncomp, False) Then
                f_Comp.Dispose()

                GC.Collect()

                ' ---------------------------- Deserialise and open!
                'Dim f_memStream As New MemoryStream(f_uncomp)
                f_ncar = CType(Deserializer.Deserialize(f_uncomp), CarBase)
                'f_uncomp.Close()
                f_uncomp.Dispose()
                f_sel = New frmCarSelection(f_ncar)
                f_sel.getConfig()
                If IsNothing(f_ncar.getConfig) Then
                    If f_sel.ShowDialog() <> Windows.Forms.DialogResult.OK Then
                        Return Nothing
                    End If
                End If

                f_sel = Nothing
                Return f_ncar
            Else
                Return Nothing
            End If
        Catch ex As Exception
            Return Nothing
        End Try
    End Function

    Private Function SecurityCheck(ByRef Array() As Byte) As Boolean
        If UBound(Array) >= 4000 Then
            Dim f_txt(6) As Byte
            array_copy(Array, 3211, f_txt, 0, 7)
            If cv_HexFromBytes(f_txt) = "3040105A669123" Then
                Return True
            Else
                Return False
            End If
        Else
            Return False
        End If
    End Function

    ''' <summary>
    ''' Verifies the data in the flash, performs all nessesary checks..
    ''' </summary>
    ''' <param name="Data"></param>
    ''' <param name="Sectors"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CheckCRC(ByVal Data() As Byte, ByVal Sectors As typFlashSector()) As typCrcVerify
        ' Calculate the CRC's
        CalculateCrc(Data, Sectors)

        ' Download the CRC's
        If Not downloadCrcs(Sectors, 0) Then
            Return typCrcVerify.failed
        End If

        Dim Query As Boolean = False

        For i As Integer = 0 To UBound(Sectors)
            If Sectors(i).nBank1CRC <> &HFFFFFFFFUI _
            Or Sectors(i).nCrc <> Sectors(i).nBank1CRC Then
                Query = True
            End If
        Next

        ' All blank, nothing to do here!
        If Not Query Then
            Return typCrcVerify.match
        Else
            Return typCrcVerify.mismatch
        End If

    End Function
End Class
